<?php
/**
 * ICore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category ICore
 * @package	 ICore_Acl
 * @copyright  Copyright (c) Igor Negrutsa progi2007@gmail.com
 * @author Igor Negrutsa
 * @license	http://framework.zend.com/license/new-bsd	   New BSD License
 */

/**
 * ICore_Acl реализует работу с ролями и ресурсами
 *
 * @category   ICore
 * @package    ICore_Acl
 * @copyright  Copyright (c) 2008 Negrutsa igor (progi2007@gmail.com)
 * @license    http://www.zend.com/license/framework/1_0.txt Zend Framework License version 1.0
 */
class Acl
{

    /**
     * @var ICore_Acl
     */
    static private $instance = null;

    /**
     * @var Zend_Acl
     */
	private $_acl;

	/**
     * @var Role model
     */
	private $_roleModel;

	/**
     * @var RoleParent model
     */
	private $_roleParentModel;

	/**
     * @var Resource model
     */
    private $_resourceModel;

    /**
     * @var Rule model
     */
    private $_ruleModel;    
    
  


    /**
     * Метод возвращает объект класса ICore_Acl
     *
     * @return object ICore_Acl
     */
    static public function getInstance()
	{
		if ( self::$instance == null ){
			self::$instance = new Acl();
		}else {
		}
		return self::$instance;
	}

	/**
     * Метод возвращает объект класса Zend_Acl
     *
     * @return object Zend_Acl
     */
	public function getAcl()
	{	    
		return $this->_acl;
	}

	/**
     * Метод инициализирует основные объекты
     * и запускает служебные методы.
     */
	private  function __construct()
	{

		$this->_acl = new Zend_Acl();
		//$this->_acl = Zend_Registry::get('acl');

		$this->_roleModel       = new Admin_Table_Role();
		$this->_roleParentModel = new Admin_Table_RoleParent();
        $this->_resourceModel   = new Admin_Table_Categories();
        $this->_ruleModel       = new Admin_Table_Rule();


		$this->_loadRoles();
		$this->_loadResources();

		$this->_loadRules();

		#Zend_Debug::dump($this->_acl);exit();
	}

	/**
     * Метод осуществляет загрузку всех ролей.
     */
	private function _loadRoles()
	{
	    $roles = $this->_roleModel->GetRoles();	    
		
	    foreach ($roles as $role){
		    $this->_loadRole($role);		
	    }	    
		
		$this->_acl->allow('admin');		
	}

	/**
     * Рекурсивный метод для загрузки ролей.
     */
    private function _loadRole($role)
	{		
		$parent = $this->_roleModel->GetRoleByID($role['parent_id']);		
		
		if(count($parent) > 0)	$this->_loadRole($parent);   		
		
		if (!$this->_acl->hasRole(new Zend_Acl_Role($role['name']))) {
		   if (count($parent) > 0){
		      $this->_acl->addRole(new Zend_Acl_Role($role['name']), array($parent['name']));
		   }else {
		      $this->_acl->addRole(new Zend_Acl_Role($role['name']));
		   }
		}
	}

	/**
     * Метод осуществляет загрузку всех ресурсов.
     */
    private function _loadResources()
    {
		$resources = $this->_resourceModel->GetResources();		
		
		foreach ($resources as $resource) {
			$this->_loadResource($resource);
		}
	}

	/**
     * Рекурсивный метод для загрузки ресурсов.
     */
    private function _loadResource($resource)
	{		
		$parent_id = $resource['parent_id'];
		
		$rname = $resource['site'].':'.$resource['module'].':'.$resource['controller'];
		
		if($parent_id > 0){
				$parent = $this->_resourceModel->GetDataRow($parent_id);
				$pname = $parent['site'].':'.$parent['module'].':'.$parent['controller'];
		}
		
		//echo $rname.' ---- '.$pname.'<br>';
		
		//$parent_id = 0;	
		
		if (!$this->_acl->has(new Zend_Acl_Resource($rname))) {
		   if ($parent_id > 0) {
		      $this->_acl->add(new Zend_Acl_Resource($rname), $pname);
		   }else {
		      $this->_acl->add(new Zend_Acl_Resource($rname));
		   }
		}
	}

	/**
     * Метод осуществляет загрузку правил.
     */
    private function _loadRules()
    {
		$rules = $this->_ruleModel->GetRuleList();
		
		foreach ($rules as $rule) {
			$assert = $rule['assert'];
			if ($assert) {
			    $assert = new $assert();
			}			
			
			//$assert = new Llib_Assert_My();		
			
			$privileges_arr = $this->_ruleModel->GetPrivilegeList($rule['id']);			
			
			if(count($privileges_arr) > 0)			
				foreach($privileges_arr as $item) $privileges[] = $item['name'];			
			else 
				$privileges = null;					
			
			switch ($rule['type']) {
				case 'allow':
					$this->_acl->allow(new Zend_Acl_Role($rule['name']), new Zend_Acl_Resource($this->_getResourceName($rule)), $privileges, $assert);
					break;
				case 'deny':
					$this->_acl->deny(new Zend_Acl_Role($rule['name']),  new Zend_Acl_Resource($this->_getResourceName($rule)), $privileges, $assert);
					break;
			}
		}
	}
	
	public function _getResourceName($res)
	{
		return $res['site'].':'.$res['module'].':'.$res['controller'];
	}

	/**
     * Вспомогательный метод для обработки и формирования массива
     *
     * @param Array
     * @return Array
     */
    private function _prepareArray($array)
    {
    	$count = count($array);
    	$temp = array();
    	for ($i = 0; $i < $count; $i++) {
    		$temp[] = $array[$i]['name'];
    	}
    	return $temp;
    }
}